//
//  ServiceManager.h
//
//
//  Created by Chen Yanjun on 12/5/12.
//  Copyright (c) 2012. All rights reserved.
//

#import "ServiceManager.h"
#import "OpenUDID.h"
#import "AFURLRequestSerialization.h"
#define AppKey     @"67e62909499a8e970c84a7c9fc71d2da"
#define AppSecret  @"ba0234e10c6c762eb6b5050a33dc5184"
typedef enum {
    RequestMethod_GET = 0,
    RequestMethod_POST,
    RequestMethod_PUT,
    RequestMethod_DELETE,
    RequestMethod_HEAD
} RequestMethod;


@interface BinaryFormData : NSObject

@property (nonatomic, strong) NSString *name;           // 提交规定的参数名称
@property (nonatomic, strong) NSString *filename;       // 文件名称
@property (nonatomic, strong) NSData *data;             // 提交需要的数据
@property (nonatomic, strong) NSString *mimeType;       // 数据类型

- (id)initWithName:(NSString *)name filename:(NSString *)filename data:(NSData *)data mimeType:(NSString *)mimeType;

@end

@implementation BinaryFormData
- (id)initWithName:(NSString *)name filename:(NSString *)filename data:(NSData *)data mimeType:(NSString *)mimeType {
    self = [super init];
    if (self) {
        self.name = name;
        self.filename = filename;
        self.data = data;
        self.mimeType = mimeType;
    }
    
    return self;
}
@end

@interface ServiceManager()

@property (readwrite, nonatomic) NSMutableDictionary *defaultHeaders;
@end

@implementation ServiceManager

+ (NSString *)HTTPRequestMethodString:(RequestMethod)requestMethod {
    NSString *method = nil;
    switch (requestMethod) {
        case RequestMethod_GET:
            method = @"GET";
            break;
            
        case RequestMethod_POST:
            method = @"POST";
            break;
            
        case RequestMethod_PUT:
            method = @"PUT";
            break;
            
        case RequestMethod_DELETE:
            method = @"DELETE";
            break;
            
        case RequestMethod_HEAD:
            method = @"HEAD";
            break;
            
        default:
            break;
    }
    
    return method;
}

+ (ServiceManager *)sharedManager{
    static ServiceManager *sServiceManager = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sServiceManager = [[ServiceManager alloc] initWithBaseURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/api", Api]]];
    });
    
    return sServiceManager;
}


- (void)sendRequestWithRequest:(NSMutableURLRequest *)request
                       success:(ServiceRequestSuccessCallback)success
                       failure:(ServiceRequestFailureCallback)failure
{
    AFJSONResponseSerializer* responseSerializer = [[AFJSONResponseSerializer alloc] init];
    responseSerializer.readingOptions = NSJSONReadingAllowFragments;
    responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", nil];
    responseSerializer.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 2)];
    responseSerializer.removesKeysWithNullValues = YES;
    
    AFURLSessionManager *sessionManagre = [AFURLSessionManager new];
    sessionManagre.responseSerializer = responseSerializer;
    sessionManagre.securityPolicy.allowInvalidCertificates = YES;
    sessionManagre.securityPolicy.validatesDomainName = NO;

    NSURLSessionDataTask *dataTask = [sessionManagre dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
#ifdef DEBUG
        NSLog(@"response: %@", responseObject);
#endif
        if (error) {
            if (failure) {
                NSString *message = error.domain ? error.domain : @"unknown error";
                if ([error.domain isEqualToString:@"NSURLErrorDomain"]
                    || [error.domain isEqualToString:@"NSCocoaErrorDomain"]) {
                    message = @"无法连接服务器，请检查网络连接";
                }
     
                failure(message);
            }

        } else {
            if ([responseObject isKindOfClass:[NSDictionary class]] && [[responseObject valueForKey:@"status"] boolValue] == NO) {
                // 部分API接口会返回error为true
                if (failure) {
                    failure(responseObject[@"error"]);
                }
            } else {
                if (success) {
                    NSDictionary *responseData = [self convertNullObject:responseObject[@"result"]];
                    success(responseObject, [responseData isKindOfClass:[NSDictionary class]] ? responseData : nil);
                }
            }
        }
    }];
    [dataTask resume];
}

- (void)requestWithUri:(NSString *)uri
                method:(RequestMethod)method
            paramaters:(NSDictionary *)parameters
               success:(ServiceRequestSuccessCallback)success
               failure:(ServiceRequestFailureCallback)failure {
    uri = [[NSString stringWithFormat:@"%@%@", self.baseURL.absoluteString, uri] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    NSError *error = nil;
    NSMutableDictionary *tokenParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];

    if ([Token sharedInstance].token) {
        NSString *random = [NSString stringWithFormat:@"%u", arc4random()];
        NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970];
        NSString *timestamp = [NSString stringWithFormat:@"%lld", (long long)timeInterval];
        NSString *sign = [[NSString stringWithFormat:@"appKey=%@&appSecret=%@&random=%@&timestamp=%@&token=%@", AppKey, AppSecret, random, timestamp, [Token sharedInstance].token] getMd5_32Bit];
        tokenParameters[@"random"] = random;
        tokenParameters[@"timestamp"] = timestamp;
        tokenParameters[@"sign"] = sign;
        tokenParameters[@"token"] = [Token sharedInstance].token;

    }
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:[[self class] HTTPRequestMethodString:method] URLString:uri parameters:tokenParameters error:&error];
#ifdef DEBUG
    NSLog(@"request url: %@", uri);
    NSLog(@"parameters: %@", tokenParameters);
#endif
    [self sendRequestWithRequest:request success:success failure:failure];
}



- (void)postMultipartWithUri:(NSString *)uri
                     useMock:(BOOL)useMock
                  parameters:(NSDictionary *)parameters
                        data:(NSDictionary *)data
                     success:(ServiceRequestSuccessCallback)success
                     failure:(ServiceRequestFailureCallback)failure {
    
    uri = [[NSString stringWithFormat:@"%@%@", self.baseURL.absoluteString, uri] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    
    NSError *error = nil;
    NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:uri relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        for (NSString *key in [data allKeys]) {
            id object = [data valueForKey:key];
            if ([object isKindOfClass:[BinaryFormData class]]) {
                BinaryFormData *bfd = (BinaryFormData *)object;
                [formData appendPartWithFileData:bfd.data name:key fileName:bfd.filename mimeType:bfd.mimeType];
            } else if ([object isKindOfClass:[NSString class]]) {
                [formData appendPartWithFormData:[((NSString *)object) dataUsingEncoding:NSUTF8StringEncoding] name:key];
            } else if ([object isKindOfClass:[NSNumber class]]) {
                [formData appendPartWithFormData:[[((NSNumber *)object) stringValue] dataUsingEncoding:NSUTF8StringEncoding] name:key];
            } else {
                [formData appendPartWithFormData:[[object description] dataUsingEncoding:NSUTF8StringEncoding] name:key];
            }
        }
    } error:&error];
    
    [self sendRequestWithRequest:request success:success failure:failure];
}

/**
 *  把response中的NSNull对象删除掉
 *
 *  @param response 要处理的对象
 *
 *  @return 删除掉NSNull后的新对象
 */
- (id)convertNullObject:(id)response
{
    if (response == nil || [response isKindOfClass:[NSNull class]]) {
        return nil;
    }
    
    if ([response isKindOfClass:[NSArray class]]) {
        NSMutableArray *tempResponse = [NSMutableArray array];
        for (id item in response) {
            id newItem = [self convertNullObject:item];
            if (newItem) {
                [tempResponse addObject:newItem];
            }
        }
        
        if (tempResponse.count > 0) {
            return tempResponse;
        } else {
            return nil;
        }
    } else if ([response isKindOfClass:[NSDictionary class]]) {
        NSMutableDictionary *tempResponse = [NSMutableDictionary dictionary];
        for (id key in [response allKeys]) {
            id value = [response objectForKey:key];
            id newValue = [self convertNullObject:value];
            if (!newValue) {
                continue;
            }
            
            [tempResponse setObject:newValue forKey:key];
        }
        
        if (tempResponse.count > 0) {
            return tempResponse;
        } else {
            return nil;
        }
    } else {
        return response;
    }
}

#pragma mark - Stub

- (id)stubWithFile:(NSString *)filename {
    NSData *stubData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:filename withExtension:@"json"]];
    NSError *error = nil;
    return [NSJSONSerialization JSONObjectWithData:stubData options:NSJSONReadingMutableContainers error:&error];
}

- (void)getTokenWithSuccess:(ServiceRequestSuccessCallback)success
                    failure:(ServiceRequestFailureCallback)failure
{
    NSString *random = [NSString stringWithFormat:@"%u", arc4random()];
    NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970];
    NSString *timestamp = [NSString stringWithFormat:@"%lld", (long long)timeInterval];
    NSString *sign = [[NSString stringWithFormat:@"appKey=%@&appSecret=%@&random=%@&timestamp=%@", AppKey, AppSecret, random, timestamp] getMd5_32Bit];
    [self requestWithUri:@"token/get"
                  method:RequestMethod_POST
              paramaters:@{@"appKey": AppKey,
                           @"random": random,
                           @"sign": sign,
                           @"timestamp": timestamp}
                 success:success
                 failure:failure];
}

- (void)refreshTokenWithSuccess:(ServiceRequestSuccessCallback)success
                        failure:(ServiceRequestFailureCallback)failure
{
    [self requestWithUri:@"token/refresh"
                  method:RequestMethod_POST
              paramaters:nil
                 success:success
                 failure:failure];
}

- (void)registerWithEmail:(NSString *)email
                 password:(NSString *)password
                 username:(NSString *)username
                  Success:(ServiceRequestSuccessCallback)success
                  failure:(ServiceRequestFailureCallback)failure
{
    NSString *openUDID = [OpenUDID value];
    if (!openUDID) {
        openUDID = @"";
    }
    [self requestWithUri:@"user/register"
                  method:RequestMethod_POST
              paramaters:@{@"parameters": @{@"device_token": openUDID,
                                            @"email": email,
                                            @"password": password,
                                            @"username": username}}
                 success:success
                 failure:failure];
}

- (void)loginWithPassword:(NSString *)password
                 username:(NSString *)username
                  Success:(ServiceRequestSuccessCallback)success
                  failure:(ServiceRequestFailureCallback)failure
{
    [self requestWithUri:@"user/login"
                  method:RequestMethod_POST
              paramaters:@{@"parameters": @{@"device_token": @"",
                                            @"password": password,
                                            @"username": username}}
                 success:success
                 failure:failure];
}

- (void)logoutWithSuccess:(ServiceRequestSuccessCallback)success
                  failure:(ServiceRequestFailureCallback)failure
{
    [self requestWithUri:@"user/logout"
                  method:RequestMethod_POST
              paramaters:nil
                 success:success
                 failure:failure];
}

@end
